home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 October: Technology Seed / ADC Seed CD - October 1999.toast / FireWire / FireWire_2.0_SDK / Source / FWiX / FWiXApp / FWiXdrag.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-04-12  |  23.1 KB  |  891 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        FWXDrag.c
  3.  
  4.     Contains:    Software to handle Finder drag copies onto FireWire File Exchange icons.
  5.  
  6.     Version:    1.0
  7.  
  8.     Written by:    Jay Lloyd
  9.  
  10.     Copyright:    © 1996-1998 by Apple Computer, Inc., all rights reserved.
  11.  
  12.     File Ownership:
  13.  
  14.         DRI:                Jay Lloyd
  15.  
  16.         Other Contact:        
  17.  
  18.         Technology:            FireWire
  19.  
  20.     Writers:
  21.  
  22.         (DCB)    Clinton Bauder
  23.         (jkl)    Jay Lloyd
  24.  
  25.     Change History (most recent first):
  26.  
  27.       <FW17>    12/19/98    DCB        More cleanup for SDK.
  28.         <16>      2/1/98    jkl        Include Errors.h.
  29.         <15>     1/15/98    jkl        Update for new headers.
  30.       <FW14>     6/19/97    jkl        Made SendFSSpecListToSelf available globally for send
  31.                                     AppleScript command.
  32.       <FW13>     5/16/97    jkl        Disposed of region handle in HandleDragTracking.
  33.       <FW12>      5/7/97    jkl        Updated data structure field names.
  34.       <FW11>     4/29/97    jkl        Made sure node drag hiliting is clipped within the scroll bars
  35.                                     and window.
  36.       <FW10>     3/18/97    jkl        Changed drag hiliting to hilite node icon and name.
  37.        <FW9>     2/27/97    jkl        Updated drag receive routine to handle window scrolling.
  38.        <FW8>     2/19/97    jkl        Fixed a problem with GetNodeInfo returning bad error message.
  39.        <FW7>      2/2/97    jkl        Corrected the DragReceive routine to only recognize a drop in a
  40.                                     node rectangle.
  41.        <FW6>     1/27/97    jkl        Changed the HandleFSItems routine to call a routine to add the
  42.                                     items to a send check queue, instead of calling a preflight
  43.                                     check and attempting send..
  44.        <FW5>     1/16/97    jkl        Added user interface features for alpha candidate. Changed
  45.                                     window handling to normal window behavior and updated drag
  46.                                     tracking for this.
  47.        <FW4>      1/8/97    ES        Changed to use FWX nodes instead of FWX drivers.
  48.        <FW3>    11/13/96    jkl        Added accessor routines to get receive node name and node info
  49.                                     record.
  50.        <FW2>    10/31/96    jkl        Added code to start check for receiver node
  51.                                     being able to handle copy. Added support for
  52.                                     multiple file/folder drops. Changed drag
  53.                                     acceptance to not accept drag if copy in progress.
  54.        <FW1>     10/2/96    jkl        initial check-in, based on DTS FinderDrag
  55. */
  56.  
  57. #include <Types.h>
  58. #include <Errors.h>
  59. #include <QuickDraw.h>
  60. #include <Files.h>
  61. #include <Controls.h>
  62. #include <AppleEvents.h>
  63. #include <Processes.h>
  64. #include <Drag.h>
  65. #include <Windows.h>
  66. #include <Devices.h>
  67. #include <Timer.h>
  68. #include <Icons.h>
  69.  
  70. #include "FWiX.h"
  71. #include "FWiXmain.h"
  72. #include "FWiXdrag.h"
  73.  
  74. #include <stdio.h>
  75. extern char  debugStr[256];
  76. static pascal void FWDebugStr(
  77.     ConstStr255Param            debuggerMsg)
  78. {
  79. #ifdef FW_DEBUG_BUILD
  80. #if FW_DEBUG_BUILD
  81.     DebugStr (debuggerMsg);
  82. #endif
  83. #endif
  84. }
  85.  
  86. //////////////////////////////////////////////////////////////////////////////
  87. //
  88. // Stupid interfaces keep changing...
  89. #if ETO_Build
  90. enum {
  91.     kDragTrackingEnterHandler    = 1,                            /* drag has entered handler*/
  92.     kDragTrackingEnterWindow    = 2,                            /* drag has entered window*/
  93.     kDragTrackingInWindow        = 3,                            /* drag is moving within window*/
  94.     kDragTrackingLeaveWindow    = 4,                            /* drag has exited window*/
  95.     kDragTrackingLeaveHandler    = 5                                /* drag has exited handler*/
  96. };
  97.  
  98. #endif
  99.  
  100. //////////////////////////////////////////////////////////////////////////////
  101. //
  102. // Internal procedure prototypes.
  103. //
  104.  
  105. OSErr InstallDragHandlers (void);    
  106.  
  107. void RemoveDragHandlers (void);
  108.     
  109. static Boolean MouseIsInContentRgn (
  110.     DragReference            theDrag,
  111.     WindowPtr                pWin);
  112.  
  113. static Boolean DragItemsAreAcceptable (
  114.     DragReference            theDrag);
  115.     
  116. static pascal OSErr HandleDragTracking (
  117.     DragTrackingMessage        theMessage,
  118.     WindowPtr                pWin,
  119.     void                    *handlerRefCon,
  120.     DragReference            theDrag);
  121.  
  122. static pascal OSErr HandleDragReceive (
  123.     WindowPtr                pWin,
  124.     void                    *handlerRefCon, 
  125.     DragReference            theDrag);
  126.     
  127. OSErr GetNodeInfo (
  128.     FWXNodeID                nodeID,
  129.     RecvNodePtr                *pRecvNode);
  130.  
  131. OSErr GetNodeDragRect (
  132.     WindowPtr            pWin,
  133.     SInt16                spaceIndex,
  134.     Rect                *iconRect,
  135.     Rect                *textRect);
  136.     
  137. OSErr GetNodeName (
  138.     WindowPtr            pWin,
  139.     SInt16                spaceIndex,
  140.     StringPtr            *pString);
  141.     
  142. static SInt16 WhichRecvNode (
  143.     WindowPtr            pWin,
  144.     Point                localPt);
  145.     
  146. static void GetNodeIDFromIndex(
  147.     SInt16                nodeIndex,
  148.     FWXNodeID            *whichNode,
  149.     WindowPtr            pWin);
  150.  
  151. static void SendDropInWindowRecvNode (
  152.     WindowPtr            pWin,
  153.     DragReference        theDrag,
  154.     FSSpecPtr            pFSSpecList,
  155.     UInt16                numInList);
  156.  
  157. pascal OSErr HandleAEFileSpecList (
  158.     AppleEvent            *pAEvent,
  159.     AppleEvent             *pReply,
  160.     SInt32                refCon);
  161.     
  162. static void HandleDragHilite (
  163.     SInt16                theMessage,
  164.     Rect                *iconRect,
  165.     Rect                *textRect);
  166.         
  167. //////////////////////////////////////////////////////////////////////////////
  168. //
  169. // External procedure prototypes.
  170. //
  171.  
  172. extern OSErr HandleFSItem (
  173.     FSSpecPtr            pFSItem,
  174.     FWXNodeID            whichNode);
  175.  
  176. //////////////////////////////////////////////////////////////////////////////
  177. //
  178. //    Globals
  179. //
  180. extern FWXAppDataPtr gpFWXAppData;
  181.  
  182. //////////////////////////////////////////////////////////////////////////////
  183. //
  184. //    InstallDragHandlers
  185. //
  186. //    InstallDragHandlers attaches tracking and receive handlers to our
  187. //    application.
  188. //    
  189. //
  190.  
  191. OSErr InstallDragHandlers (void)
  192. {
  193.     DragTrackingHandlerUPP        pDragTracker = nil;
  194.     DragReceiveHandlerUPP        pDragReceiver = nil;
  195.     OSErr                         err = noErr;
  196.     
  197.     gpFWXAppData->dragReceiveHandlerInstalled = false;
  198.     gpFWXAppData->dragTrackingHandlerInstalled = false;
  199.     
  200.     //    Create and install the drag tracker
  201.     pDragTracker = NewDragTrackingHandlerProc(HandleDragTracking);
  202.     if (pDragTracker != nil) {
  203.         //    We allocated the procpointer, install it.
  204.         err = InstallTrackingHandler(pDragTracker, nil, nil);
  205.     
  206.         if (err == noErr) {
  207.             //    We installed the drag tracker.
  208.             gpFWXAppData->dragTrackingHandler = pDragTracker;
  209.             gpFWXAppData->dragTrackingHandlerInstalled = true;
  210.         } else {
  211.             //    The drag tracker was allocated but not installed,
  212.             //    dispose of the routine descriptor.
  213.             DisposeRoutineDescriptor(pDragTracker);
  214.             return err;
  215.         }
  216.     } else {
  217.         //    We could not allocate the proc pointer
  218.         return memFullErr;
  219.     }
  220.     
  221.     //    Create and install the drag receiver. If we got this far,
  222.     //    the drag tracker is installed.
  223.     pDragReceiver = NewDragReceiveHandlerProc(HandleDragReceive);
  224.     if (pDragReceiver != nil) {
  225.         //    We allocated the procpointer, install it.
  226.         err = InstallReceiveHandler(pDragReceiver, nil, nil);
  227.     
  228.         if (err == noErr) {
  229.             //    We installed the drag receiver.
  230.             gpFWXAppData->dragReceiveHandler = pDragReceiver;
  231.             gpFWXAppData->dragReceiveHandlerInstalled = true;
  232.         } else {
  233.             //    The drag receiver was allocated but not installed,
  234.             //    dispose of the routine descriptor, clean up the tracker.
  235.             DisposeRoutineDescriptor(pDragReceiver);
  236.             RemoveTrackingHandler(pDragTracker, nil);
  237.             DisposeRoutineDescriptor(pDragTracker);
  238.             gpFWXAppData->dragTrackingHandlerInstalled = false;
  239.             return err;
  240.         }
  241.     } else {
  242.         //    We could not allocate the proc pointer, clean up the tracker.
  243.         RemoveTrackingHandler(pDragTracker, nil);
  244.         DisposeRoutineDescriptor(pDragTracker);
  245.         gpFWXAppData->dragTrackingHandlerInstalled = false;
  246.         return memFullErr;
  247.     }
  248.             
  249.     return err;
  250. }
  251.  
  252.  
  253. //////////////////////////////////////////////////////////////////////////////
  254. //
  255. //    RemoveDragHandlers
  256. //
  257. //    Remove the drag handlers from a window prior to closing the window.
  258. //
  259.  
  260. void RemoveDragHandlers (void)
  261. {    
  262.     if (gpFWXAppData->dragReceiveHandlerInstalled) {
  263.         RemoveReceiveHandler(gpFWXAppData->dragReceiveHandler , nil);
  264.         DisposeRoutineDescriptor(gpFWXAppData->dragReceiveHandler);
  265.     }
  266.     
  267.     if (gpFWXAppData->dragTrackingHandlerInstalled) {
  268.         RemoveTrackingHandler(gpFWXAppData->dragTrackingHandler, nil);
  269.         DisposeRoutineDescriptor(gpFWXAppData->dragTrackingHandler);
  270.     }
  271. }
  272.  
  273.  
  274. //////////////////////////////////////////////////////////////////////////////
  275. //
  276. //    MouseInContentRgn
  277. //
  278. //    returns true if the mouse is in the content area of the window
  279. //    (not necessarily in the visible rgn)
  280. //
  281.  
  282. static Boolean MouseIsInContentRgn (
  283.     DragReference            theDrag,
  284.     WindowPtr                pWin)
  285. {
  286.     Point                    mousePt;
  287.     
  288.     GetDragMouse(theDrag, &mousePt, nil);
  289.     
  290.     return PtInRgn(mousePt, ((WindowPeek) pWin)->contRgn);
  291. }
  292.  
  293.  
  294. //////////////////////////////////////////////////////////////////////////////
  295. //
  296. //    DragItemsAreAcceptable
  297. //
  298. //    Returns true if the contents (data) of the drag
  299. //    are acceptable. Its a file or folder.
  300. //
  301. //    Called by the tracking and receive handlers
  302. //
  303.  
  304. static Boolean DragItemsAreAcceptable(
  305.     DragReference        theDrag)
  306. {
  307.     OSErr                err;
  308.     UInt16                numItems;
  309.     UInt16                indexItem;
  310.     ItemReference        itemRef;
  311.     FlavorFlags            theFlags;
  312.  
  313.     if (gpFWXAppData->pSenderWindow != FrontWindow())
  314.         return false;
  315.         
  316.     //    loop through each item in the drag to make sure it has an HFS flavor
  317.     err = CountDragItems(theDrag, &numItems);
  318.     if (err == noErr) {
  319.         for (indexItem = 1; indexItem <= numItems; indexItem++) {
  320.  
  321.             err = GetDragItemReferenceNumber(theDrag, indexItem, &itemRef);
  322.  
  323.             if (err == noErr) {
  324.                 err = GetFlavorFlags(theDrag, itemRef, flavorTypeHFS, &theFlags );
  325.                 if (err != noErr)
  326.                     return false;    // drag item is not hfs, its all or nothing
  327.             } else
  328.                 return false;        // could not get item reference
  329.         }
  330.     } else {
  331.         return false;                // could not count items
  332.     }
  333.         
  334.     return true;                    // each item is an hfs (should always be that way)
  335. }
  336.  
  337. //////////////////////////////////////////////////////////////////////////////
  338. //
  339. //    HandleDragTracking
  340. //
  341. //    Called by the drag manager whenever a drag is
  342. //    over one of our windows. On entry the current
  343. //    port has been set to our windows by the Drag Manager.
  344. //
  345.  
  346. static pascal OSErr HandleDragTracking (
  347.     DragTrackingMessage        theMessage,
  348.     WindowPtr                pWin,
  349.     void                    *handlerRefCon,
  350.     DragReference            theDrag)
  351. {
  352. //#pragma unused handlerRefCon
  353.     WindowDataPtr            pWinData;
  354.     RgnHandle                hOldClip;
  355.     Rect                    iconRect, textRect, drawRect;
  356.     Point                    localPt;
  357.     SInt16                    mouseInWhichSpace;
  358.     SInt16                    deltaH, deltaV;
  359.     OSErr                    err = noErr;
  360.     
  361.     switch (theMessage)
  362.     {    
  363.         case kDragTrackingEnterHandler:            
  364.             // Initialization for the handler
  365.             (gpFWXAppData->dragHandlerGlobals).acceptableDragFlag = 
  366.                 DragItemsAreAcceptable(theDrag);
  367.             (gpFWXAppData->dragHandlerGlobals).hilitedSpace = kNoSpace;
  368.             HandleDragHilite(kHiliteInit, &iconRect, &textRect);
  369.             
  370.             // let the drag manager know if we can't accept this drag
  371.             if (!(gpFWXAppData->dragHandlerGlobals).acceptableDragFlag)
  372.                 err = dragNotAcceptedErr;
  373.             break;
  374.             
  375.         case kDragTrackingEnterWindow: 
  376.         case kDragTrackingInWindow:
  377.         case kDragTrackingLeaveWindow:            
  378.             // Handle highlighting the receive node icon
  379.             if (gpFWXAppData->dragHandlerGlobals.acceptableDragFlag)
  380.             {
  381.                 pWinData = (WindowDataPtr) GetWRefCon(pWin);
  382.                 deltaH = GetControlValue(pWinData->hHScrollBar);
  383.                 deltaV = GetControlValue(pWinData->hVScrollBar);
  384.                 SetOrigin(deltaH, deltaV);
  385.                 GetClip(hOldClip = NewRgn());
  386.                 drawRect = pWin->portRect;
  387.                 drawRect.bottom -= kScrollBarAdjust;
  388.                 drawRect.right -= kScrollBarAdjust;
  389.                 ClipRect(&drawRect);
  390.                 
  391.                 // Unless the mouse is leaving the visible area of the
  392.                 // window, check if it's in the window's content region
  393.                 if (theMessage == kDragTrackingLeaveWindow)
  394.                     mouseInWhichSpace = kNoSpace;
  395.                 else
  396.                 {
  397.                     GetDragMouse(theDrag, &localPt, nil);
  398.                     GlobalToLocal(&localPt);
  399.                     mouseInWhichSpace = WhichRecvNode(pWin, localPt);
  400.                 }
  401.  
  402.                 // If the mouse's space is not equal to the hilitedSpace
  403.                 // and the mouse is in a space  (i.e., a new, different space.)
  404.                 if ((mouseInWhichSpace != gpFWXAppData->dragHandlerGlobals.hilitedSpace) &&
  405.                     (mouseInWhichSpace != kNoSpace))
  406.                 {
  407.                     if (gpFWXAppData->dragHandlerGlobals.hilitedSpace != kNoSpace)
  408.                     {        
  409.                         // There is a currently hilited space, unhilite it
  410.                         GetNodeDragRect (pWin,
  411.                                          gpFWXAppData->dragHandlerGlobals.hilitedSpace,
  412.                                          &iconRect,
  413.                                          &textRect);
  414.                         HandleDragHilite(kHiliteOff, &iconRect, &textRect);
  415.                     }
  416.  
  417.                     // draw the hilight
  418.                     GetNodeDragRect(pWin, mouseInWhichSpace, &iconRect, &textRect);
  419.                     HandleDragHilite(kHiliteOn, &iconRect, &textRect);
  420.                     gpFWXAppData->dragHandlerGlobals.hilitedSpace = mouseInWhichSpace;                    
  421.                 }
  422.                 // else if the mouse is not in the content region
  423.                 // and an icon is hilighted, erase the hilight
  424.                 else if ((mouseInWhichSpace == kNoSpace) &&
  425.                          (gpFWXAppData->dragHandlerGlobals.hilitedSpace != kNoSpace))
  426.                 {
  427.                     GetNodeDragRect (pWin,
  428.                                      gpFWXAppData->dragHandlerGlobals.hilitedSpace,
  429.                                      &iconRect,
  430.                                      &textRect);
  431.                     HandleDragHilite(kHiliteOff, &iconRect, &textRect);
  432.                     gpFWXAppData->dragHandlerGlobals.hilitedSpace = kNoSpace;
  433.                 }
  434.                 SetOrigin(0, 0);
  435.                 SetClip(hOldClip);
  436.                 DisposeRgn(hOldClip);
  437.             }
  438.             break;
  439.  
  440.         // do nothing for the leaveHandler message
  441.         case kDragTrackingLeaveHandler:
  442.             HandleDragHilite(kHiliteDispose, &iconRect, &textRect);
  443.             break;
  444.         
  445.         // let the drag manager know if we didn't recognize the message
  446.         default:
  447.             err = paramErr;
  448.     }
  449.     return err;
  450. }
  451.  
  452. //////////////////////////////////////////////////////////////////////////////
  453. //
  454. //    HandleDragHilite
  455. //
  456. //    Handle hiliting of node icons in sender window
  457. static void HandleDragHilite (
  458.     SInt16                theMessage,
  459.     Rect                *iconRect,
  460.     Rect                *textRect)
  461. {
  462.     static Handle        hIconSuite;
  463.     OSErr                err;
  464.  
  465.     switch (theMessage)
  466.     {
  467.         case kHiliteInit:
  468.             err = GetIconSuite(&hIconSuite, kDropIconSuiteID, svAllAvailableData);
  469.             break;
  470.         case kHiliteOff:
  471.             err = PlotIconSuite(iconRect, atNone, ttNone, hIconSuite);
  472.             InvertRect(textRect);
  473.             break;
  474.         case kHiliteOn:
  475.             err = PlotIconSuite(iconRect, atNone, ttSelected, hIconSuite);
  476.             InvertRect(textRect);
  477.             break;
  478.         case kHiliteDispose:
  479.             err = DisposeIconSuite(hIconSuite, false);
  480.     }
  481. }
  482.  
  483. //////////////////////////////////////////////////////////////////////////////
  484. //
  485. //    HandleDragReceive
  486. //
  487. //    Called by the drag manager when a drag ends in our window
  488. //
  489. //    Need to loop through each drag item and get its hfs data
  490. //    building a list of fsspec's as we go.
  491. //
  492. //    Send an AppleEvent to ourselves to handle copying the list.
  493. //
  494.  
  495. static pascal OSErr HandleDragReceive (
  496.     WindowPtr                pWin,
  497.     void                    *handlerRefCon, 
  498.     DragReference            theDrag)
  499. {
  500. //#pragma unused handlerRefCon
  501.     
  502.     ItemReference            itemRef;
  503.     Size                    flavorDataSize;
  504.     FSSpecPtr                pFSSpecList;
  505.     HFSFlavor                itemHFSFlavor;
  506.     UInt16                    numItems;
  507.     UInt16                    indexItem;
  508.     OSErr                    err = noErr;
  509.     
  510.     if (! (DragItemsAreAcceptable(theDrag) && MouseIsInContentRgn(theDrag, pWin)))
  511.         return dragNotAcceptedErr;
  512.  
  513.     err = CountDragItems(theDrag, &numItems);
  514.     if (err == noErr)
  515.     {
  516.         //    allocate a buffer to grab each of the drag items FSSpecs
  517.         pFSSpecList = (FSSpecPtr) NewPtr(sizeof(FSSpec) * numItems);
  518.         if (pFSSpecList == nil)
  519.             return memFullErr;
  520.         
  521.         for (indexItem = 1; indexItem <= numItems; indexItem++) {
  522.             // reset flavorDataSize through each loop
  523.             // as it gets updated by the GetFlavorData call
  524.             flavorDataSize = sizeof(HFSFlavor);
  525.             
  526.             err = GetDragItemReferenceNumber(theDrag, indexItem, &itemRef);
  527.             if (err != noErr) {
  528.                 DisposePtr((Ptr)pFSSpecList);
  529.                 return err;
  530.             }
  531.             
  532.             err = GetFlavorData(theDrag, itemRef, flavorTypeHFS, 
  533.                                 &itemHFSFlavor, &flavorDataSize, 0);
  534.             if (err != noErr) {
  535.                 DisposePtr((Ptr)pFSSpecList);
  536.                 return err;
  537.             }
  538.             pFSSpecList[indexItem-1] = itemHFSFlavor.fileSpec;
  539.         }
  540.         if (err == noErr)
  541.             SendDropInWindowRecvNode(pWin, theDrag, pFSSpecList, numItems);
  542.  
  543.         DisposePtr((Ptr)pFSSpecList);
  544.     }
  545.     return err;
  546. }
  547.  
  548. //////////////////////////////////////////////////////////////////////////////
  549. //
  550. //    SendSetterToSelf
  551. //
  552. //    Send an AppleEvent to ourself with the firewire file exchange
  553. //    receive node ID and the FSSpec list of items to be sent.
  554. //
  555.  
  556. OSErr SendFSSpecListToSelf (
  557.     FWXNodeID                fwxNodeID,
  558.     FSSpecPtr                pFSSpecList,
  559.     UInt16                    numFSSpecs)
  560. {
  561.     AppleEvent                send;
  562.     AppleEvent                reply;
  563.     AEDesc                    selfTarget;
  564.     ProcessSerialNumber        psn;
  565.     UInt32                    longFSSpecCount;
  566.     OSErr                    err;
  567.  
  568.     longFSSpecCount = numFSSpecs;
  569.     selfTarget.dataHandle = nil;
  570.     send.dataHandle = nil;
  571.  
  572.     GetCurrentProcess(&psn);
  573.     err = AECreateDesc(typeProcessSerialNumber, (Ptr) &psn, sizeof(ProcessSerialNumber), &selfTarget);
  574.     if (err != noErr)
  575.         return err;
  576.     
  577.     err = AECreateAppleEvent(kAEFWXEventClass, kAEFileSpecList, &selfTarget, 
  578.             kAutoGenerateReturnID, kAnyTransactionID, &send);
  579.     if (err != noErr) {
  580.         AEDisposeDesc(&selfTarget);
  581.         return err;
  582.     }
  583.         
  584.     err = AEPutParamPtr(&send, kAEFWXNodeIDKey, kAEFWXNodeIDType, (Ptr) &fwxNodeID, sizeof(FWXNodeID));
  585.     if (err != noErr) {
  586.         AEDisposeDesc(&selfTarget);
  587.         if (send.dataHandle != nil)
  588.             AEDisposeDesc(&send);
  589.         return err;
  590.     }
  591.  
  592.     err = AEPutParamPtr(&send, kAEFSSpecKey, typeFSS, (Ptr) pFSSpecList, sizeof(FSSpec)*numFSSpecs);
  593.     if (err != noErr) {
  594.         AEDisposeDesc(&selfTarget);
  595.         if (send.dataHandle != nil)
  596.             AEDisposeDesc(&send);
  597.         return err;
  598.     }
  599.     
  600.     err = AEPutParamPtr(&send, kAEFSSpecCountKey, typeLongInteger, (Ptr) &longFSSpecCount, sizeof(UInt32));
  601.     if (err != noErr) {
  602.         AEDisposeDesc(&selfTarget);
  603.         if (send.dataHandle != nil)
  604.             AEDisposeDesc(&send);
  605.         return err;
  606.     }
  607.  
  608.     err = AESend(&send, &reply, kAENoReply + kAEAlwaysInteract + kAECanSwitchLayer,
  609.                 kAENormalPriority, kAEDefaultTimeout, nil, nil);
  610.  
  611.     if (err != noErr) {
  612.         AEDisposeDesc(&selfTarget);
  613.         AEDisposeDesc(&send);
  614.     }
  615.  
  616.     return err;
  617. }
  618.  
  619. //////////////////////////////////////////////////////////////////////////////
  620. //
  621. //    GetNodeInfo
  622. //
  623. //    Return the nodeInfo record for the node id.
  624. //
  625.  
  626. OSErr GetNodeInfo (
  627.     FWXNodeID            nodeID,
  628.     RecvNodePtr            *pRecvNode)
  629. {
  630.     WindowPtr            pWin;
  631.     WindowDataPtr        pWinData;
  632.     RecvNodePtr            pTempRecvNode;
  633.     SInt16                index;
  634.     OSErr                err = noErr;
  635.     
  636.     pWin = gpFWXAppData->pSenderWindow;
  637.     pWinData = (WindowDataPtr) GetWRefCon(pWin);
  638.         
  639.     pTempRecvNode = pWinData->pRecvNodeList;
  640.     for (index = 0; index < pWinData->numRecvNodes; index++) {
  641.         if (pTempRecvNode->nodeID == nodeID)
  642.             break;
  643.         pTempRecvNode = (RecvNodePtr) pTempRecvNode->pNextNode;
  644.     }
  645.  
  646.     *pRecvNode = pTempRecvNode;
  647.     if (pTempRecvNode == nil)
  648.         err = resNotFound;     // JKL *** what error?
  649.  
  650.     return err;
  651. }
  652.  
  653.  
  654. //////////////////////////////////////////////////////////////////////////////
  655. //
  656. //    GetNodeName
  657. //
  658. //    Get the bounding rectangle of a drag area for the specified index.
  659. //    There is a drag area for each FireWire Exchange node.
  660. //
  661.  
  662. OSErr GetNodeName (
  663.     WindowPtr            pWin,
  664.     SInt16                nodeIndex,
  665.     StringPtr            *pString)
  666. {
  667.     WindowDataPtr        pWinData;
  668.     RecvNodePtr            pTempRecvNode;
  669.     SInt16                index;
  670.     
  671.     pWinData = (WindowDataPtr) GetWRefCon(pWin);
  672.     if (nodeIndex > pWinData->numRecvNodes)
  673.         return memFullErr;        // JKL - some error
  674.         
  675.     pTempRecvNode = pWinData->pRecvNodeList;
  676.     for (index = 1; index < nodeIndex; index++) {
  677.         pTempRecvNode = (RecvNodePtr) pTempRecvNode->pNextNode;
  678.     }
  679.  
  680.     *pString = pTempRecvNode->nodeName;
  681.  
  682.     return noErr;
  683. }
  684.  
  685.  
  686. //////////////////////////////////////////////////////////////////////////////
  687. //
  688. //    GetNodeDragRect
  689. //
  690. //    Get the bounding rectangle of a drag area for the specified index.
  691. //    There is a drag area for each FireWire Exchange node.
  692. //
  693.  
  694. OSErr GetNodeDragRect (
  695.     WindowPtr            pWin,
  696.     SInt16                nodeIndex,
  697.     Rect                *iconRect,
  698.     Rect                *textRect)
  699. {
  700.     WindowDataPtr        pWinData;
  701.     RecvNodePtr            pTempRecvNode;
  702.     SInt16                index;
  703.     
  704.     pWinData = (WindowDataPtr) GetWRefCon(pWin);
  705.     if (nodeIndex > pWinData->numRecvNodes)
  706.         return memFullErr;        // JKL - some error
  707.         
  708.     pTempRecvNode = pWinData->pRecvNodeList;
  709.     for (index = 1; index < nodeIndex; index++) {
  710.         pTempRecvNode = (RecvNodePtr) pTempRecvNode->pNextNode;
  711.     }
  712.  
  713.     *iconRect = pTempRecvNode->recvNodeIconRect;
  714.     *textRect = pTempRecvNode->recvNodeTextRect;
  715.  
  716.     return noErr;
  717. }
  718.  
  719.  
  720. //////////////////////////////////////////////////////////////////////////////
  721. //
  722. //    WhichRecvNode
  723. //
  724. //    Determine where the drop has taken place. There is a space for each
  725. //    FireWire Exchange node. After doing a compare it will return the space
  726. //    number, or kNoSpace if it didn't land in a space.
  727. //
  728.  
  729. SInt16 WhichRecvNode (
  730.     WindowPtr            pWin,
  731.     Point                localPt)
  732. {
  733.     WindowDataPtr        pWinData;
  734.     RgnHandle            iconRgn, textRgn, dragRgn;
  735.     Rect                iconRect;
  736.     Rect                textRect;
  737.     SInt16                count;
  738.     SInt16                theNodeIndex;
  739.     
  740.     pWinData = (WindowDataPtr) GetWRefCon(pWin);
  741.     theNodeIndex = kNoSpace;
  742.     if (pWinData == nil)
  743.         return theNodeIndex;
  744.     
  745.     iconRgn = NewRgn();
  746.     textRgn = NewRgn();
  747.     dragRgn = NewRgn();
  748.     if (pWinData != nil)
  749.     {
  750.         for (count = 1; count <= pWinData->numRecvNodes; count ++)
  751.         {            
  752.             GetNodeDragRect(pWin, count, &iconRect, &textRect);
  753.             RectRgn(iconRgn, &iconRect);
  754.             RectRgn(textRgn, &textRect);
  755.             UnionRgn(iconRgn, textRgn, dragRgn);
  756.             if (PtInRgn(localPt, dragRgn))
  757.             {
  758.                 theNodeIndex = count;
  759.                 break;
  760.             }
  761.         }
  762.     }
  763.     DisposeRgn(iconRgn);
  764.     DisposeRgn(textRgn);
  765.     DisposeRgn(dragRgn);
  766.     return theNodeIndex;
  767. }
  768.  
  769. //////////////////////////////////////////////////////////////////////////////
  770. //
  771. //    GetNodeIDFromIndex
  772. //
  773. //    Using an index into the list of receive nodes, get the FireWire File
  774. //    Exchange node id from the indexed node.
  775. //
  776.  
  777. static void GetNodeIDFromIndex(
  778.     SInt16                nodeIndex,
  779.     FWXNodeID            *whichNode,
  780.     WindowPtr            pWin)
  781. {
  782.     WindowDataPtr        pWinData;
  783.     RecvNodePtr            pTempRecvNode;
  784.     SInt16                i;
  785.     
  786.     pWinData = (WindowDataPtr) GetWRefCon(pWin);
  787.     *whichNode = kInvalidFWXNodeID;
  788.     
  789.     if (pWinData != nil) {
  790.         
  791.         if (nodeIndex <= pWinData->numRecvNodes) {
  792.             pTempRecvNode = pWinData->pRecvNodeList;
  793.             for (i = 1; i < nodeIndex; i++) {
  794.                 pTempRecvNode = (RecvNodePtr) pTempRecvNode->pNextNode;
  795.             }
  796.     
  797.             *whichNode = pTempRecvNode->nodeID;
  798.         }
  799.     }
  800. }
  801.         
  802. //////////////////////////////////////////////////////////////////////////////
  803. //
  804. //    SendDropInWindowRecvNode
  805. //
  806. //    Get the drag location, convert it to local coordinates. Find which receive
  807. //    node the drop occurred in and send us an AppleEvent with the list of FSSpec's.
  808. //
  809.  
  810. static void SendDropInWindowRecvNode (
  811.     WindowPtr            pWin,
  812.     DragReference        theDrag,
  813.     FSSpecPtr            pFSSpecList,
  814.     UInt16                numInList)
  815. {
  816.     Point                 thePoint;
  817.     GrafPtr                oldPort;
  818.     FWXNodeID            whichFWXNode = (FWXNodeID) kInvalidFWXNodeID;
  819.     SInt16                theNodeIndex;
  820.     OSErr                err;
  821.  
  822.     GetPort(&oldPort);
  823.     SetPort(pWin);
  824.     GetDragMouse(theDrag, &thePoint, 0L);
  825.     GlobalToLocal(&thePoint);
  826.     theNodeIndex = WhichRecvNode(pWin, thePoint);
  827.     SetPort(oldPort);
  828.     
  829.     if (theNodeIndex != kNoSpace)
  830.         GetNodeIDFromIndex(theNodeIndex, &whichFWXNode, pWin);
  831.  
  832.     if (whichFWXNode != (FWXNodeID) kInvalidFWXNodeID)
  833.         err = SendFSSpecListToSelf(whichFWXNode, pFSSpecList, numInList);
  834. }
  835.  
  836. //////////////////////////////////////////////////////////////////////////////
  837. //
  838. //    HandleAEFileSpecList
  839. //
  840. //    Pull parameters out of AppleEvent and call routine to handle the drop.
  841. //
  842.  
  843. pascal OSErr HandleAEFileSpecList (
  844.     AppleEvent            *pAEvent,
  845.     AppleEvent             *pReply,
  846.     SInt32                refCon)
  847. {
  848. //#pragma unused pReply
  849. //#pragma unused refCon
  850.  
  851.     OSErr                err;
  852.     DescType            returnType;
  853.     Size                returnSize;
  854.     FWXNodeID            whichNode;
  855.     UInt32                numFSSpecs;
  856.     FSSpecPtr            pFSSpec;
  857.     UInt16                index;
  858.  
  859.     err = AEGetParamPtr(pAEvent, kAEFWXNodeIDKey, kAEFWXNodeIDType, &returnType,
  860.                         (Ptr) &whichNode, sizeof(FWXNodeID), &returnSize);
  861.     if (err != noErr)
  862.         return err;
  863.  
  864.     err = AEGetParamPtr(pAEvent, kAEFSSpecCountKey, typeLongInteger, &returnType,
  865.                         (Ptr) &numFSSpecs, sizeof(SInt32), &returnSize);
  866.     if (err != noErr)
  867.         return err;
  868.  
  869.     pFSSpec = (FSSpecPtr) NewPtr(sizeof(FSSpec) * numFSSpecs);
  870.     if (pFSSpec == nil)
  871.         return memFullErr;
  872.         
  873.     err = AEGetParamPtr(pAEvent, kAEFSSpecKey, typeFSS, &returnType,
  874.                         (Ptr) pFSSpec, sizeof(FSSpec) * numFSSpecs, &returnSize);
  875.     if (err != noErr)
  876.         return err;
  877.  
  878.     for (index = 0; index < numFSSpecs; index++) {
  879.         err = HandleFSItem(&pFSSpec[index], whichNode);
  880.         if (err != noErr) {
  881.             sprintf(debugStr, "Error in HandleFileList: %d", err);
  882.             FWDebugStr((ConstStr255Param) c2pstr(debugStr));
  883.             break;
  884.         }
  885.     }
  886.     
  887.     DisposePtr((Ptr) pFSSpec);
  888.     
  889.     return err;
  890. }
  891.